package base;


import interfaccia.*;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

public class Base {
	private static final String HOST="localhost";
	private String nome;
	private BaseGui gui;
	private BaseImpl baseImpl;
	protected Vector<IAutotreno> parcheggio;
	private Vector<IBase> codaLavori;
	private Vector<IBase> spedizioniAttive;
	private TGestioneOrdini gestioneOrdini;
	Base(String str)throws Exception{
		nome= new String(str);
		gui = new BaseGui(nome);
		baseImpl = new BaseImpl();
		parcheggio= new Vector<IAutotreno>();
		codaLavori = new Vector<IBase>();
		spedizioniAttive = new Vector<IBase>();
		baseImpl.run();		
	}
	class BaseImpl extends UnicastRemoteObject implements IBase {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private IDitta ditta;
		public BaseImpl()throws RemoteException {}
				
		public void run() throws Exception {
			try {
				ditta = (IDitta) Naming.lookup("rmi://"+HOST+"/Ditta");
				
				if(ditta.registrazioneBase(this,nome)){
					System.out.println("base " + nome + " creata con successo");
					gui.attivazioneBase();
					gestioneOrdini=new TGestioneOrdini(ditta, (IBase) this);
				}
				else{
					System.out.println("impossibile creare base " + nome);
					gui.setVisible(false);
				}
				
				
				//invoca il metodo remoto
				//System.out.println("msg ricevuto:" + ref.registrazioneBase());
			} catch (MalformedURLException e) {
				System.out.println("Impossibile trovare nel registro RMI");
				e.printStackTrace();
			} catch (RemoteException e) {
				System.out.println("Eccezione sul server");
				e.printStackTrace();
			} catch (NotBoundException e) {
				System.out.println("lookup() non è riuscito a trovare il server Ditta nel registro RMI");
				e.printStackTrace();
			}
		}

		@Override
		public String nomeBase() throws RemoteException {
			return nome;
		}
		
		public  void parcheggia(IAutotreno me) throws RemoteException {
			IAutotreno auto=me;
			synchronized(parcheggio){
				parcheggio.addElement(auto);
				try {
					//System.out.println("Parcheggio autotreno " + auto.nomeAutotreno() + " effettuato con successo");
					gui.parcheggio(auto.nomeAutotreno(), 0);
				} catch (RemoteException e) {
					e.printStackTrace();
				}
				parcheggio.notifyAll();
			}
		}

		@Override
		public boolean lasciaParcheggio(IAutotreno autotreno)
				throws RemoteException {
			synchronized(parcheggio){
				gui.parcheggio(autotreno.nomeAutotreno(), 1);
				boolean x = parcheggio.remove(autotreno);
				parcheggio.notifyAll();
				return x;
			}
		}

		@Override
		public void aggiungiConsegna(IBase destinatario, int quantita)
				throws RemoteException {
			System.out.println("Aggiungendo " + quantita +" nuove consegne.");
			while (quantita>0){
				codaLavori.add(destinatario);
				quantita--;
			}
			gestioneOrdini.attivaGestioneTrasporti();
			//if(parcheggio.size()>0){
				synchronized(codaLavori){
					codaLavori.notify();
					
				}
			//}
		}
		
		
		@Override
		public Vector<IAutotreno> listaAutotreni() throws RemoteException {
			return parcheggio;
		}
		
		public String listaAutotreniString() throws RemoteException{
			int sizea=parcheggio.size();
			String str="";
			int it=0;
			synchronized(parcheggio)
				{
					while(it<sizea){
						str+= parcheggio.elementAt(it).nomeAutotreno() +" ";
						it++;
					}
					parcheggio.notifyAll();
				}
			return str;
		}

		@Override
		public void segnalaViaLibera(IBase base) throws RemoteException {
			synchronized(spedizioniAttive)
			{
				for(int x=0;x<spedizioniAttive.size();++x){
					if(spedizioniAttive.elementAt(x).equals(base))
						spedizioniAttive.remove(x);
				
				}
				spedizioniAttive.notifyAll();

			}
		}

		@Override
		public String codaLavoriString() throws RemoteException {
			int size=codaLavori.size();
			String str="";
			int it=0;
			//System.out.print(listaNomiBasi.elementAt(it)+" Autotreni: " );
			synchronized(codaLavori)
				{
					while(it<size){
						str+= codaLavori.elementAt(it).nomeBase() +" ";
						it++;
					}
					codaLavori.notifyAll();
				}
			synchronized(spedizioniAttive)
			{
				int itx=0;
				size=spedizioniAttive.size();
				str+=" linee attive:";
				while(itx<size){
					str+= spedizioniAttive.elementAt(it).nomeBase() +" ";
					itx++;
				}
				spedizioniAttive.notifyAll();
			}
			return str;

		}

		@Override
		public void interrompiAttivita() throws RemoteException {
			if(gestioneOrdini!=null){
				if(!gestioneOrdini.isAlive())
					gestioneOrdini.start();
				else
					gestioneOrdini.interrupt();
				if(gestioneOrdini.isInterrupted())
					System.out.println("INTERROTTO");
			}
			for(int i=0;i<parcheggio.size();++i){
					try{
						parcheggio.elementAt(i).quit();
					}
					catch(Exception e)
					{
						System.out.println("Autotreno nel parcheggio di " + nome + " eliminato");
					}
				}
		}

		@Override
		public void quit() throws RemoteException {
			quitBase(0);
		}

		@Override
		public boolean ciSei() throws RemoteException {
			return true;
		}
	}
	void quitBase(int x){
		System.exit(x);
	}

	class TRegistrazioneBase extends Thread {
		IDitta ditta;
		IBase base;
		String nomeBase;
		/*
		 * costruttore della classe TRegistrazioneBase
		 */
		public TRegistrazioneBase(IBase baseref) {
			setDaemon(true);
			base=baseref;
		}
		/*

		 */

		public void run() {
			
			
			try {
				
				ditta = (IDitta) Naming.lookup("rmi://"+HOST+"/Ditta");
				//ditta.registrazioneBase(base, nomeBase);
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				return;
			} catch (RemoteException e) {
				return;
				//e.printStackTrace();
			} catch (NotBoundException e) {
				return;
			}
		}
	}

	class TGestioneOrdini extends Thread {
		IDitta ditta;
		IAutotreno autotreno;
		IBase base;
		/*
		 * costruttore della classe TGestioneOrdini
		 */
		public TGestioneOrdini(IDitta dittaref,IBase baseref) {
			ditta=dittaref;
			base=baseref;
		}
		public void attivaGestioneTrasporti() {
			if(!this.isAlive()) //caution che non termini
				this.start();
			else
				return;
		}
		/*
		 * override del metodo run della classe Thread.
		 */
		
		
	/*	public void run(){
			try {
				while(true){
					synchronized(codaLavori){
						while(codaLavori.isEmpty())
						{
							System.out.println("codalavori.wait");
							codaLavori.wait();
						}synchronized(parcheggio){
							while(parcheggio.isEmpty()){
								System.out.println("parcheggio.wait "+parcheggio.size());
								parcheggio.wait();				
							}
							for(int i=0;i<codaLavori.size();++i){
								if(!spedizioniAttive.contains(codaLavori.elementAt(i))){
									System.out.println("Sto lanciando un autocarro verso " + codaLavori.elementAt(i).nomeBase());
									IAutotreno a=parcheggio.firstElement();
									base.lasciaParcheggio(a);
									a.impostaViaggio(base, codaLavori.firstElement());
									synchronized(spedizioniAttive){
										spedizioniAttive.add(codaLavori.elementAt(0));
										//System.out.println("Spedizione attiva "+ spedizioniAttive.elementAt(0).nomeBase());
										spedizioniAttive.notifyAll();
									}
									codaLavori.removeElementAt(0);
								}
							}
							parcheggio.notifyAll();
						}
						codaLavori.notifyAll();
					}
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				try {
					System.out.println("Base: " + base.nomeBase() +" ha interrotto le operazioni");
					ditta.riuscitaChiusura(base.nomeBase());
					
				} catch (RemoteException e1) {
					e1.printStackTrace();
				}
				return;
				//e.printStackTrace();
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}*/
		
		public void run(){
			try {
				while(true){

					synchronized(codaLavori){
						while(codaLavori.isEmpty())
						{
							codaLavori.wait();				
						}
					}
					
					synchronized(parcheggio){
						while(parcheggio.isEmpty())
						{
							parcheggio.wait();
						}
						

						
						for(int i=0;i<codaLavori.size();++i){
							if(!spedizioniAttive.contains(codaLavori.elementAt(i))){
								System.out.println("Sto lanciando un autocarro verso " + codaLavori.elementAt(i).nomeBase());
								IAutotreno a=parcheggio.firstElement();
								base.lasciaParcheggio(a);
								a.impostaViaggio(base, codaLavori.firstElement());
								synchronized(spedizioniAttive){
									spedizioniAttive.add(codaLavori.elementAt(0));
									//System.out.println("Spedizione attiva "+ spedizioniAttive.elementAt(0).nomeBase());
									spedizioniAttive.notifyAll();
								}
								codaLavori.removeElementAt(0);
							}
						}
					}
				}
			}
				catch (InterruptedException e) {
				// TODO Auto-generated catch block
				try {
					System.out.println("Base: " + base.nomeBase() +" ha interrotto le operazioni");
					ditta.riuscitaChiusura(base.nomeBase());
					
				} catch (RemoteException e1) {
					e1.printStackTrace();
				}
				return;
				//e.printStackTrace();
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}// -------- Class 
}
